package tech.xs.sys.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import tech.xs.common.auth.domain.enums.AuthPathWhiteTypeEnum;
import tech.xs.common.domain.enums.ImportTypeEnum;
import tech.xs.common.framework.domain.annotations.AuthApi;
import tech.xs.common.framework.domain.constant.DatePattern;
import tech.xs.common.framework.domain.constant.FileSuffixConstant;
import tech.xs.common.framework.domain.entity.BaseEntity;
import tech.xs.common.framework.domain.entity.TreeEntity;
import tech.xs.common.framework.domain.model.ApiResult;
import tech.xs.common.framework.domain.model.PageResult;
import tech.xs.common.framework.util.Assert;
import tech.xs.common.sys.domain.constant.PermissionConstant;
import tech.xs.common.util.FieldUtil;
import tech.xs.sys.domain.bo.web.menu.*;
import tech.xs.sys.domain.entity.SysWebMenu;
import tech.xs.sys.service.SysWebMenuService;
import tech.xs.sys.service.SysWebMenuShowService;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

@Slf4j
@Validated
@RestController
@RequestMapping("/web/menu")
public class SysWebMenuController {

    @Resource
    private SysWebMenuShowService sysWebMenuShowService;
    @Resource
    private SysWebMenuService sysWebMenuService;

    @PostMapping("/saveOrUpdate")
    @AuthApi(permissions = PermissionConstant.MENU_MGR)
    public ApiResult<SysWebMenu> manualEdit(@Validated @RequestBody EditWebMenuBo bo) {
        bo.checkParameter();

        String fatherCode = bo.getFatherCode();
        if (StrUtil.isNotBlank(fatherCode)) {
            if (fatherCode.equals(bo.getCode())) {
                return ApiResult.error("父菜单编码不能是自身编码");
            }
            long existCount = sysWebMenuService.count(Wrappers.<SysWebMenu>lambdaQuery()
                    .eq(SysWebMenu::getCode, fatherCode));
            if (existCount <= 0) {
                return ApiResult.error("父菜单不存在");
            }
        }


        long existCount = sysWebMenuService.count(Wrappers.<SysWebMenu>lambdaQuery()
                .eq(SysWebMenu::getCode, bo.getCode())
                .ne(bo.getId() != null, BaseEntity::getId, bo.getId()));
        if (existCount > 0) {
            return ApiResult.error("菜单编码已经存在");
        }

        SysWebMenu saveData = new SysWebMenu();
        BeanUtil.copyProperties(bo, saveData);
        if (bo.getId() != null) {
            SysWebMenu dbData = sysWebMenuService.getOne(Wrappers.<SysWebMenu>lambdaQuery().eq(BaseEntity::getId, bo.getId()));
            if (dbData == null) {
                return ApiResult.error("根据id在系统中未查询到数据");
            }
        }

        log.info("更新或保存菜单:" + saveData);
        sysWebMenuService.saveOrUpdate(saveData);
        return ApiResult.success(saveData);
    }

    @DeleteMapping("/delete/code")
    @AuthApi(permissions = PermissionConstant.MENU_MGR)
    public ApiResult<String> deleteByCode(@RequestParam String menuCode) {
        if (StrUtil.isBlank(menuCode)) {
            return ApiResult.error("[menuCode]不能为空");
        }
        long count = sysWebMenuService.count(Wrappers.<SysWebMenu>lambdaQuery().eq(SysWebMenu::getCode, menuCode));
        if (count <= 0) {
            return ApiResult.error("菜单不存在或已删除:" + menuCode);
        }
        log.info("删除菜单:" + menuCode);
        sysWebMenuService.remove(Wrappers.<SysWebMenu>lambdaQuery().eq(TreeEntity::getCode, menuCode));
        return ApiResult.success(menuCode);
    }

    @GetMapping("/routes")
    @AuthApi(type = AuthPathWhiteTypeEnum.LOGIN)
    public ApiResult<GetWebRouteBo> getCurrUserRoutes() throws Exception {
        return ApiResult.success(sysWebMenuShowService.getCurrUserRoutes());
    }

    /**
     * 导出菜单
     */
    @PostMapping("/export")
    @AuthApi(permissions = PermissionConstant.MENU_MGR)
    public ResponseEntity<List<ImportExportWebMenuBo>> exportWebMenu(@RequestBody ExportWebMenuQueryBo bo) {
        String fileName = "菜单导出_" + DateUtil.format(new Date(), DatePattern.UNSIGNED_NORM_DATETIME_PATTERN) + FileSuffixConstant.JSON;
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));
        headers.add(HttpHeaders.CONTENT_TYPE, "application/json");

        List<ImportExportWebMenuBo> res = new ArrayList<>();
        if (CollUtil.isNotEmpty(bo.getIds())) {
            List<SysWebMenu> dbData = sysWebMenuService.list(bo.query());
            for (SysWebMenu dbItem : dbData) {
                ImportExportWebMenuBo exportItem = new ImportExportWebMenuBo();
                BeanUtil.copyProperties(dbItem, exportItem);
                exportItem.setImportType(ImportTypeEnum.addOrUpdate);
                res.add(exportItem);
            }
        }
        return ResponseEntity.ok().headers(headers).body(res);
    }

    /**
     * 导入菜单
     */
    @PostMapping("/import")
    @AuthApi(permissions = PermissionConstant.MENU_MGR)
    public ApiResult<Void> importWebMenu(@NotNull @RequestParam("file") MultipartFile file) throws IOException {
        String json = new String(file.getBytes());
        Set<String> importFatherCodes = new HashSet<>();
        Set<String> existFatherCodes = new HashSet<>();
        List<ImportExportWebMenuBo> importMenus = JSONObject.parseArray(json, ImportExportWebMenuBo.class);
        log.info("开始导入菜单:" + importMenus);
        for (ImportExportWebMenuBo importMenu : importMenus) {
            Assert.isNotBlank(importMenu.getCode(), "菜单编码不能为空");
            Assert.isNotBlank(importMenu.getName(), "菜单名称不能为空");
            Assert.isNotBlank(importMenu.getShowName(), "菜单展示名称不能为空");
            if (StrUtil.isNotBlank(importMenu.getFatherCode())) {
                importFatherCodes.add(importMenu.getFatherCode());
            }
        }
        for (ImportExportWebMenuBo importMenu : importMenus) {
            for (String importFatherCode : importFatherCodes) {
                if (importFatherCode.equals(importMenu.getCode())) {
                    existFatherCodes.add(importFatherCode);
                }
            }
        }
        if (!importFatherCodes.isEmpty()) {
            List<SysWebMenu> dbFatherMenu = sysWebMenuService.list(Wrappers.<SysWebMenu>lambdaQuery().in(TreeEntity::getCode, importFatherCodes));
            for (SysWebMenu fatherMenu : dbFatherMenu) {
                existFatherCodes.add(fatherMenu.getCode());
            }
        }
        if (importFatherCodes.size() != existFatherCodes.size()) {
            importFatherCodes.removeAll(existFatherCodes);
            return ApiResult.error("父菜单不存在" + JSONArray.toJSONString(importFatherCodes));
        }
        sysWebMenuService.importWebMenu(importMenus);
        log.info("菜单导入成功:" + importMenus);
        return ApiResult.success();
    }

    @GetMapping("/list/all")
    @AuthApi(permissions = PermissionConstant.MENU_MGR)
    public ApiResult<List<SysWebMenu>> listAll() {
        return ApiResult.success(sysWebMenuService.list(Wrappers.<SysWebMenu>lambdaQuery().orderByAsc(SysWebMenu::getOrderValue)));
    }

    @GetMapping("/list/page")
    @AuthApi(permissions = PermissionConstant.MENU_MGR)
    public PageResult<SysWebMenu> listPage(@ModelAttribute PageWebMenuBo bo) {
        Page<SysWebMenu> page = sysWebMenuService.page(bo.page(), bo.query());
        List<SysWebMenu> records = page.getRecords();
        // 设置父菜单
        Set<String> fatherCodes = FieldUtil.toSet(records, TreeEntity::getFatherCode);
        if (CollUtil.isNotEmpty(fatherCodes)) {
            List<SysWebMenu> menus = sysWebMenuService.list(Wrappers.<SysWebMenu>lambdaQuery().in(SysWebMenu::getCode, fatherCodes).orderByAsc(SysWebMenu::getOrderValue));
            Map<String, SysWebMenu> menuMap = FieldUtil.toMap(menus, TreeEntity::getCode);
            for (SysWebMenu record : records) {
                if (StrUtil.isBlank(record.getFatherCode())) {
                    continue;
                }
                record.setFather(menuMap.get(record.getFatherCode()));
            }
        }
        return PageResult.success(page);
    }

}
